////////////////////////////////////////////////////////////////////////////////////
/* Program: This file contains modules necessary to implement the Decision 
 *			Layer of SENTINEL Project.  Specifically, the Target Listen,
 *			Coordinate Parser, Position Turret, and Fire Command modules are
 *			contained in this file.
 * Author:	Robert Wunderlich
 * Editors: Ryan Bell, Eric Cleveland, Sean Pierce (Team PAINTeK)
 * Purpose: Necessary for the SENTINEL system to keep track of what mode the
 *			system is in and which targets and commands to pass on to the
 *			Execution Layer.  Accepts socket input from Image Processing and
 *			User Interface Layers.  Outputs via sockets to the UI Layer and
 *			function calls to the Execution Layer.
 * Misc:	
 */

/* *************** Reference: **************************
	The Winsock code contained in this file was obtained from the MSDN Library:
	http://msdn.microsoft.com/en-us/library/ms740632%28v=vs.85%29

	/** comments were used to represent where function calls to the Execution
	Layer need to be inserted in the final code when the layers are inegrated.

	//D comments were used to remove output that was used for debugging

	//T code represents lines of code that were originally used to create a
	new thread each time activity occurred on the socket for mode changes.
	This code was not deleted in case it becomes necessary to implement a
	separate thread for each mode change event.

	//U comments were used to remove output that was used for Unit Testing

************************************************** */

#ifndef _TARGETLISTENER_H_
#define _TARGETLISTENER_H_

#include <winsock2.h>
#include <ws2tcpip.h>
#include <iostream>
#include <stdio.h>
//#include <string>
#include "Thread.h"

//#include "ExecutionLayer\Execution Layer.cpp"

// Port used to listen for targets
#define PORT "5566"

// Number of attempts to fire at a target received from the UI Layer in
// Remote mode
#define NUMSHOTS 1

#pragma comment(lib, "Ws2_32.lib")

class TargetListener
{
public:
	void Run( DecisionLayerVariable* GV );
	bool IsThreadActive();
	// *********************************************************
	// public test code
	void Test_FireCommand( DecisionLayerVariable* GV );
	void Test_PositionTurret( DecisionLayerVariable* GV );
	void Test_Listen();
	void Test_CoordinateParser( DecisionLayerVariable* GV );
	
private:
	Lib::Thread<TargetListener, DecisionLayerVariable* > m_thread;
	
	void Listen( DecisionLayerVariable *GV );
	void CoordinateParser(std::string CSCoordinate, DecisionLayerVariable* GV);
	bool PositionTurret(int x, int y, bool fire, DecisionLayerVariable* GV);
	void FireCommand( DecisionLayerVariable* GV );
	int ExtractSource( std::string CSCoordinate2);
	int ExtractX(std::string CSCoordinate);
	int ExtractY(std::string CSCoordinate);
	// *********************************************************
	// private test code
	bool TEST_PT_OHVCP_R(int x, int y, bool fire);
	bool TEST_FC_OHCR_R();
	void TEST_FC_OHF();
};

// ----------------------------------------
void TargetListener::Run( DecisionLayerVariable* GV )
{
	m_thread.Run(this, &TargetListener::Listen, GV);
}

// ----------------------------------------
bool TargetListener::IsThreadActive()
{
	return m_thread.IsThreadActive();
}

// ----------------------------------------
void TargetListener::Listen( DecisionLayerVariable* GV )
/*	The Receive Target module establishes a UDP socket connection with the Image Processing Layer and UI Layer to
	listen for new target coordinates. Once received, this module forwards the coordinates to the Coordinate Parser
	module.
*/
{
//D	std::cout << "thread >" << i << "< ran\n"; // test code to verify thread and parameter passed
	
	//winsock startup
	WSADATA wsaData;
	sockaddr_in SenderAddr;
    int SenderAddrSize = sizeof (SenderAddr);

	int error = WSAStartup( MAKEWORD(2,2), &wsaData); // fill in WSA info
	
	if(error != 0) // failed to startup winsock
	{
		std::cout << "WSAStartup failed: " << error << "\n";
	}

	struct addrinfo *result = NULL, *ptr = NULL, hints;

	ZeroMemory(&hints, sizeof(hints));
	hints.ai_family = AF_INET;
	hints.ai_socktype = SOCK_DGRAM;
	hints.ai_protocol = IPPROTO_UDP;
	hints.ai_flags = AI_PASSIVE;

	// Resolve the local address and port to be used by the server
	error = getaddrinfo(NULL, PORT, &hints, &result);

	if(error !=0)
	{
		std::cout << "getaddrinfo failed: " << error << "\n";
		WSACleanup();
	}

	SOCKET ListenSocket;

	// Create a SOCKET for the server to listen for client

	ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);

	if(ListenSocket == INVALID_SOCKET)
	{
		std::cout << "Error at socket(): " << WSAGetLastError() << "\n";
		freeaddrinfo(result);
		WSACleanup();
	}

	// Setup the listening socket
	error = bind(ListenSocket, result->ai_addr, (int)result->ai_addrlen);

	if(error == SOCKET_ERROR)
	{
		std::cout << "bind failed with error: " << WSAGetLastError() << "\n";
		freeaddrinfo(result);
		WSACleanup();
	}

	freeaddrinfo(result);

	int recvbuflen = 10;
	char recvbuf[10];
	

	// receive until the peer shuts down the connection
	do
	{
//D		std::cout << "C: mode: " << *mode << " waiting for socket activity...\n";
		error = recvfrom(ListenSocket, recvbuf, recvbuflen, 0, (SOCKADDR *) & SenderAddr, &SenderAddrSize);
		if(error > 0)
		{
//D			std::cout << "Source: " << ExtractSource(recvbuf, mode) << "\n";
//D			std::cout << "Mode: " << mode << "\n";
//D			std::cout << error << ": " << CSCoordinate << "\n";

			//CoordinateParser(recvbuf, mode, Sentinel);
			CoordinateParser(recvbuf, GV);

//D			std::cout << recvbuf << "\n";

//T			CoordinateThread test1;
//T			test1.Run(recvbuf);
			
			// testing to see if thread runs successfully, giving it
			// time to print a test message
//T			while (test1.IsThreadActive())
//T			::Sleep( 1000 );
		}
		else if(error == 0)
			std::cout << "connection closed\n";
		else
			std::cout << "recv failed: " << WSAGetLastError() << "\n";
	}
	while(error > 0);
}

// ----------------------------------------
void TargetListener::CoordinateParser(std::string CSCoordinate, DecisionLayerVariable* GV)
/*  This module will generate coordinate and fire commands that are sent to the
	Turret Controller subsystem based on the current mode. If the system is in
	Standby mode, no coordinates will be forwarded. If the system is in Test mode,
	coordinates from the Image Processing Layer will be forwarded. If the system
	is in Battle mode, coordinates from the Image Processing Layer will be
	forwarded along with the fire command. If the system is in Remote mode,
	coordinates from the UI Layer will be forwarded along with the fire command.
*/
{
//U	std::cout << "CoordinateParser(\"" << CSCoordinate << "\", " << *mode << ")\n";

	//int source;
	//int XCoord = ExtractX(CSCoordinate);
	//int YCoord = ExtractY(CSCoordinate
	int count;

	switch(ExtractSource(CSCoordinate))
	{
	case 0: //coordinates came from Image Processing Layer
		//switch(*mode)
		switch(GV->mode)
		{
		case 0: // Standby
//D			std::cout << "do nothing\n";
			break;
		case 1: // Test
//D			std::cout << "send coordinates, do not fire\n";
			//PositionTurret(ExtractX(CSCoordinate), ExtractY(CSCoordinate), false, Sentinel);
			PositionTurret(ExtractX(CSCoordinate), ExtractY(CSCoordinate), false, GV);
			break;
		case 2: // Battle
//D			std::cout << "send coordinates, fire\n";
			//PositionTurret(ExtractX(CSCoordinate), ExtractY(CSCoordinate), true, Sentinel);
			PositionTurret(ExtractX(CSCoordinate), ExtractY(CSCoordinate), true, GV);
			break;
		case 3: // Remote
//D			std::cout << "do nothing\n";
			break;
		default:
			std::cout << "ERROR: unrecognized mode value\n";
		}
		break;
	case 1: //coordinates came from User Interface Layer
		//switch(*mode)
		switch(GV->mode)
		{
		case 0: // Standby
//D			std::cout << "do nothing\n";
			break;
		case 1: // Test
//D			std::cout << "do nothing\n";
			break;
		case 2: // Battle
//D			std::cout << "do nothing\n";
			break;
		case 3: // Remote
			count = NUMSHOTS;
			while(!PositionTurret(ExtractX(CSCoordinate), ExtractY(CSCoordinate), true, GV) && (GV->mode == 3) && (count > 0))
			{
				count--;
				::Sleep(100);
			}
			// end of loop
			break;
		default:
			std::cout << "ERROR: unrecognized mode value\n";
		}
		break;
	default: //unrecognized source
		std::cout << "ERROR: unrecognized source value\n";
	}
}

// ----------------------------------------
bool TargetListener::PositionTurret(int x, int y, bool fire, DecisionLayerVariable* GV)
/*	The Coordinate Parser module passes a target coordinate along with a value
	representing whether to fire at the target. The target coordinates are sent
	to the Execution layer to position the turret. If the fire value is set to
	true, then this module will check the return from the Execution layer to
	ensure that the turret is in position before issuing the fire command.
*/
{
//D	std::cout << "PositionTurret(" << x << ", " << y << ", " << fire << ")\n";
//D	std::cout << "	output handlerVCP(" << x << ", " << y << ", " << fire << ")\n";

	bool fireCommandIssued;// = false;

/**/fireCommandIssued = GV->Sentinel->setTarget(x,y);

	if(fire /*&& fireCommandIssued*/) // call Virtual Coordinate Processer and check return
	
//U		std::cout << "		return value: " << TEST_PT_OHVCP_R(x,y,fire) << "\n";
		
		FireCommand( GV );
	

	return fireCommandIssued;
}

// ----------------------------------------
void TargetListener::FireCommand( DecisionLayerVariable* GV )
/*	The Fire Command module is a function that can be called by the Position
	Turret module. Once initiated, the Fire Command module will check the range
	and then forward the fire command to the Execution Layer if the target is not
	within 5 meters from the turret.
*/
{
//D	std::cout << "	output handlerCR()\n";
//D	std::cout << "		return value: " << TEST_FC_OHCR_R() << "\n";



/**/if(TEST_FC_OHCR_R() ) // call function to check range before firing
	{
//D			printf("Trying to fire\n");
/**/		GV->Sentinel->Sendfire(); // call function to fire gun
	}
}

// ----------------------------------------
int TargetListener::ExtractSource(std::string CSCoordinate)
/*	The Extract Source module reades the third value in a comma separated string
	and returns the value.  Returns -1 if unable to extract the source.
*/
{
	int CommaCount = 0;
	for(int i=0; i < CSCoordinate.size(); i++)
	{
		if(CommaCount == 2)
			return CSCoordinate[i] - '0';
		else if(CSCoordinate[i] == ',')
			CommaCount++;
	}
	return -1;
}

// ----------------------------------------
int TargetListener::ExtractX(std::string CSCoordinate)
/*	The Extract X module reades the first value in a comma separated string and
	returns the value.  Returns -1 if unable to extract the X coordinate.
*/
{
	std::string XValue = "";
	for(int i=0; i < CSCoordinate.size(); i++)
	{
		if(CSCoordinate[i] == ',')
		{
			XValue = CSCoordinate.substr(0,i);
//D			std::cout << "->" << XValue << "<-\n";
			return atoi(XValue.c_str());
		}
	}
	return -1;
}

// ----------------------------------------
int TargetListener::ExtractY(std::string CSCoordinate)
/*	The Extract Y module reades the second value in a comma separated string and
	returns the value.  Returns -1 if unable to extract the Y coordinate.
*/
{
	int begin = -1;
	std::string YValue = "";
	for(int i=0; i < CSCoordinate.size(); i++)
	{
		if(CSCoordinate[i] == ',' && (begin < 0))
		{
//D			std::cout << "i set to: " << i << "\n";
			begin = i+1;
		}
		else if(CSCoordinate[i] == ',' && (begin > 0))
		{
//D			std::cout << "end is: " << i << "\n";
			YValue = CSCoordinate.substr(begin,i-begin);
//D			std::cout << "->" << YValue << "<-\n";
			return atoi(YValue.c_str());
		}
	}
	return -1;
}
// ****************************************
// PRIVATE TEST FUNCTIONS //
// ----------------------------------------
bool TargetListener::TEST_PT_OHVCP_R(int x, int y, bool fire)
/*	Test function for the PositionTurret module's function call to the output
	handler's to Virtual Coordinate processer.  This provides a return so that
	the PositionTurret module can proceed.
*/

{
	return true;
}

// ----------------------------------------
bool TargetListener::TEST_FC_OHCR_R()
/*	Test function for the FireCommand module's function call to the Check Range
	function.  This provides a return so that the FireCommand module can proceed.
*/
{
	return true;
}

// ----------------------------------------
void TargetListener::TEST_FC_OHF()
/*	Test function for the FireCommand module's function call to act as a place
	holder where the actual function call to the output handler will be called.
*/
{
//D	std::cout << "	Fire command issued\n";
}

// ****************************************
// PUBLIC TEST FUNCTIONS //
// ----------------------------------------
//void TargetListener::Test_FireCommand( ExecutionLayer* Sentinel )
void TargetListener::Test_FireCommand( DecisionLayerVariable* GV )
/*	Test ID: UI3
	This is a test function for the Fire Command module.  If TEST_FC_OHCR_R() is
	set to return "true", then this test should result in the function call to
	fire the gun.  If TEST_FC_OHCR_R() is set to return false, then this test
	should NOT make the function call to fire the gun.
*/
{
	//FireCommand( Sentinel );
	FireCommand( GV );
}

// ----------------------------------------
//void TargetListener::Test_PositionTurret( ExecutionLayer* Sentinel)
void TargetListener::Test_PositionTurret( DecisionLayerVariable* GV )
/*	Test ID: UI4
	This is a test function for the Position Turret module.  If passing a fire
	value of false, should not call FireCommand() regardless of return from
	TEST_FC_OHVCP_R().  If passing a fire value of true, should call FireCommand()
	if TEST_FC_OHVCP_R() returns true, and not if TEST_FC_OHVCP_R() returns false.
*/
{
	//PositionTurret(150,30,true, Sentinel);
	PositionTurret(150,30,true, GV);
}

// ----------------------------------------
void TargetListener::Test_Listen()
/*	Test ID: UI5
	This is a test function for the Target Listener module.  After running this
	function, writing to socket 5566 should result in a function call to the
	CoordinateParser module passing the CSV string received on the socket along
	with a reference to the global mode variable.
*/
{
	int test_mode = 1;
	//Listen(&test_mode);
}

// ----------------------------------------
//void TargetListener::Test_CoordinateParser( ExecutionLayer* Sentinel)
void TargetListener::Test_CoordinateParser( DecisionLayerVariable* GV )
/*	Test ID: UI6
	This is a test function for the Coordinate Parser module.  Coordinates and
	fire commands should be passed to the PositionTurret module based on the
	source and the current mode.
*/
{
	int test_mode = 3;
	//CoordinateParser("0,0,1", &test_mode, Sentinel);
}

#endif
